

#include "CenterLinePanel.h"

#include "VolumeSource.h"

#include "vtkLineSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkPropPicker.h"
#include "vtkDecimatePro.h"
#include "vtkPolyDataMapper.h"
#include "vtkTriangleFilter.h"
#include "vtkSmoothPolyDataFilter.h"
#include "vtkButterflySubdivisionFilter.h"
#include "vtkDiscreteMarchingCubes.h"
#include "vtkWarpVector.h"
#include "vtkWindowedSincPolyDataFilter.h"


#include "itkImageMaskSpatialObject.h"
#include "itkAutoCropLabelMapFilter.h"
#include "itkCastImageFilter.h"
#include "itkFastChamferDistanceImageFilter.h"
#include "itkApproximateSignedDistanceMapImageFilter.h"
#include "itkSignedDanielssonDistanceMapImageFilter.h"
#include <itkRegionOfInterestImageFilter.h>


CenterLinePanel::CenterLinePanel(QWidget *parent) : ControlPanelBase(parent)
{
	m_ui.setupUi(this);
	m_panelType = ptCenterLine;
	m_pDistanceMap = NULL;
	m_ballDisplayingView = NULL;
	m_sourceSkeleton = NULL;
	m_sourceLiver = NULL;

	m_iSizeSphere = NULL; 
	m_pIndexSphereX = NULL;
	m_pIndexSphereY = NULL;
	m_pIndexSphereZ = NULL;

	connect(m_ui.m_btnExtractCenterLine, SIGNAL(clicked()), SLOT(slotExtractCenterLine()));
	connect(m_ui.m_btnLoadMask, SIGNAL(clicked()), SLOT(slotLoadMask()));
	//connect(m_ui.m_btnLiverDivision2, SIGNAL(clicked()), SLOT(slotLiverDivision2()));
	//connect(m_ui.m_btnLiverDivision4, SIGNAL(clicked()), SLOT(slotLiverDivision4()));
	connect(m_ui.m_btnProcessMask, SIGNAL(clicked()), SLOT(slotProcessMask()));

	connect(m_ui.m_btnSave, SIGNAL(clicked()), SLOT(slotSaveBranchPoints()));
	connect(m_ui.m_btnLoad, SIGNAL(clicked()), SLOT(slotLoadBranchPoints()));
	connect(m_ui.m_btnShowAll, SIGNAL(clicked()), SLOT(slotShowAllPoints()));
	connect(m_ui.m_btnClearAll, SIGNAL(clicked()), SLOT(slotClearAllPoints()));
	connect(m_ui.m_btnSeparation, SIGNAL(clicked()), SLOT(slotLocateHepaticVein()));
	//connect(m_ui.m_sliderUpper, SIGNAL(valueChanged(int)), SLOT(slotSliderUpperMoved(int)));
	//connect(m_ui.m_sliderLower, SIGNAL(valueChanged(int)), SLOT(slotSliderLowerMoved(int)));
	connect(m_ui.m_btnTesting1, SIGNAL(clicked()), SLOT(slotTesting1()));
	connect(m_ui.m_btnTesting2, SIGNAL(clicked()), SLOT(slotTesting2()));
	connect(m_ui.m_btnTesting3, SIGNAL(clicked()), SLOT(slotTesting3()));

	connect(m_ui.m_btnRebuildVessel,SIGNAL(clicked()), SLOT(slotRebuildVessel()));
	connect(m_ui.m_btnRemoveVessel,SIGNAL(clicked()), SLOT(slotRemoveVessel()));
	connect(m_ui.m_btnRemoveHepatic,SIGNAL(clicked()), SLOT(slotRemoveHepatic()));

	connect(m_ui.m_btnLocatePortal, SIGNAL(clicked()), SLOT(slotLocatePortalPoint()));
	connect(m_ui.m_btnAutoLeftLiver, SIGNAL(clicked()), SLOT(slotAutoLeftLiver()));
	connect(m_ui.m_btnAutoRightLiver, SIGNAL(clicked()), SLOT(slotAutoRightLiver()));
	connect(m_ui.m_btnAutoClassifyBranches, SIGNAL(clicked()), SLOT(slotAutoClassifyBranches()));

	connect(m_ui.m_btnD2Skeleton, SIGNAL(clicked()), SLOT(slotSetSkeletonSource()));
	connect(m_ui.m_btnD2Liver, SIGNAL(clicked()), SLOT(slotSetLiverSource()));

	connect(m_ui.m_btnTestClips, SIGNAL(clicked()), SLOT(slotTestClips()));
	connect(m_ui.m_btnSMVolume,  SIGNAL(clicked()), SLOT(slotSmoothVolume()));
	connect(m_ui.m_btnSMSurface,  SIGNAL(clicked()), SLOT(slotCreateSmoothSurface()));

	m_pickingCallBack = PickingCallBackForVesselSeparation::New();
	m_pickingCallBack->combox = m_ui.m_cbSeedList;
}

void CenterLinePanel::slotSetSkeletonSource()
{
	if (m_ui.m_btnD2Skeleton->isChecked()==false)
	{
		m_sourceSkeleton = NULL;
		qDebug() << "set skeleton source NULL";
	}
	else
	{
		m_sourceSkeleton = currentSource();
		qDebug() << "set skeleton source as current source" << currentSource()->text();
	}
}

void CenterLinePanel::slotSetLiverSource()
{
	if (m_ui.m_btnD2Liver->isChecked()==false)
	{
		m_sourceLiver = NULL;
		qDebug() << "set liver source NULL";
	}
	else
	{
		m_sourceLiver = currentSource();
		qDebug() << "set liver source as current source" << currentSource()->text();
	}
}



void CenterLinePanel::slotAutoLeftLiver()
{
	if ( m_sourceSkeleton == NULL)
	{
		qDebug() << "[warning] please choose a skeleton volume";
		return;
	}

	if ( m_ui.m_btnWithLiver->isChecked() && m_sourceLiver == NULL)
	{
		qDebug() << "[warning] please choose a liver volume";
		return;
	}


	switch(m_sourceSkeleton->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		autoDivideLeftLiver<unsigned char>();
		break;
	case VTK_SHORT:
		autoDivideLeftLiver<short>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}
}


void CenterLinePanel::slotAutoClassifyBranches()
{
	if ( m_sourceSkeleton == NULL)
	{
		qDebug() << "[warning] please choose a skeleton volume";
		return;
	}

	if ( m_ui.m_btnWithLiver->isChecked() && m_sourceLiver == NULL)
	{
		qDebug() << "[warning] please choose a liver volume";
		return;
	}


	switch(m_sourceSkeleton->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		autoClassifyBranches<unsigned char>();
		break;
	case VTK_SHORT:
		autoClassifyBranches<short>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}
}

	
void CenterLinePanel::slotAutoRightLiver()
{

}


void CenterLinePanel::slotExtractCenterLine()
{
	Source *source = currentSource();

	if ( !source || source->type() != stVolume)
	{
		qDebug() << "[Liver]: Source is not a Volume";
		return;
	}

	switch(currentSource()->dataType())
	{
	case VTK_UNSIGNED_CHAR:
			createCenterLineThread<unsigned char>();
			break;
	case VTK_SHORT:
			createCenterLineThread<short>();
			break;
	case VTK_FLOAT:
			createCenterLineThread<float>();
			break;
	default:
			qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
			break;
	}
}

void CenterLinePanel::slotLoadMask()
{
	m_currentMaskFile = QFileDialog::getOpenFileName(this,
		tr("Load Liver Mask"), "", tr("Mask Files (*.bin *.vtk)"));

	if ( m_currentMaskFile.isEmpty())
		return;

	std::cout << "Mask file: " << m_currentMaskFile.toLatin1().data() << std::endl;
}

void CenterLinePanel::slotProcessMask()
{
	Source *source = currentSource();

	if ( !source || source->type() != stVolume)
	{
		std::cout << "Source is not a Volume" << std::endl;
		return;
	}

	if ( m_currentMaskFile.isEmpty())
	{
		std::cout << "Load Liver Mask first!" << std::endl;
		return;
	}

	switch(currentSource()->dataType())
	{
	case VTK_UNSIGNED_CHAR:
			createMaskedVolume<unsigned char>();
			break;
	case VTK_SHORT:
			createMaskedVolume<short>();
			break;
	case VTK_FLOAT:
			createMaskedVolume<float>();
			break;
	default:
			qDebug() << "[Warning]: Doesn't support data type " 
				<< currentSource()->dataType();
			break;
	}

}




void CenterLinePanel::slotLiverDivision2()
{
	//QVector<int> seed1 = m_seedPoints[m_sourceSeed->text()];
	//QVector<int> seed2 = m_seedPoints[m_sourceSkeleton->text()];

	//m_ui.m_textInfo->append(QString("%1,%2,%3").arg(seed1[0]).arg(seed1[1]).arg(seed1[2]));

	switch(m_sourceSkeleton->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		liverDivision<unsigned char>();
		break;
	case VTK_SHORT:
		liverDivision<short>();
		break;
	case VTK_FLOAT:
		liverDivision<float>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}
}

void CenterLinePanel::slotPointsSelected()
{
	slotSelectSeed();
}

void CenterLinePanel::setSource( const QModelIndex& index )
{
	ControlPanelBase::setSource(index);

	Source *source = currentSource();
	if (source->type() != stVolume)
	{
		return;
	}

// 	if ( !source->fileName().isEmpty())
// 	{
// 		int pos = source->fileName().find("skeleton");
// 
// 	}

	if ( m_ui.m_btnD2Skeleton->isChecked()==false)
	{
		m_ui.m_leD2Skeleton->setText(currentSource()->text());
		//m_sourceSkeleton = source;
	}

	if ( m_ui.m_btnD2Liver->isChecked()==false)
	{
		m_ui.m_leD2Liver->setText(currentSource()->text()) ;
		//m_sourceLiver = source;
	}

	switch(source->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		m_currentSpacing = getCurrentSpacing<unsigned char>();
		break;
	case VTK_SHORT:
		m_currentSpacing = getCurrentSpacing<unsigned char>();
		break;
	case VTK_FLOAT:
		m_currentSpacing = getCurrentSpacing<unsigned char>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}

	m_pickingCallBack->spacing[0] = m_currentSpacing[0];
	m_pickingCallBack->spacing[1] = m_currentSpacing[1];
	m_pickingCallBack->spacing[2] = m_currentSpacing[2];
}

void CenterLinePanel::setDisplayModel( DisplayModel* dm )
{
	ControlPanelBase::setDisplayModel(dm);
	m_pickingCallBack->m_displayModel = dm;

	connect(m_displayModel->displayFramework()->getActive3DView(), SIGNAL(emitKeyEvent(QKeyEvent*)),
		this, SLOT(slotProcessKeyEventFromView(QKeyEvent*)));
	m_displayModel->displayFramework()->getActive3DView()->setProperPickingMode(m_pickingCallBack);
}

void CenterLinePanel::slotSelectSeed()
{
	Source *source = currentSource();

	if ( !source || source->type() != stVolume)
	{
		std::cout << "Source is not a Volume" << std::endl;
		return;
	}

	switch(currentSource()->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		processSelectedPoints<unsigned char>();
		break;
	case VTK_SHORT:
		processSelectedPoints<short>();
		break;
	case VTK_FLOAT:
		processSelectedPoints<float>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}

}

static bool sort_nodes(Node node1, Node node2)
{
	return node1.time > node2.time;
}


void CenterLinePanel::slotCenterLineProgressDone()
{
	int num;
	double spacing[4];

	switch(currentSource()->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		num = ((CenterLineThread<unsigned char>*)m_threadCenterLineExtraction)->GetBranchAndExtremePoints(m_vectorControlPoints);
		m_pDistanceMap = ((CenterLineThread<float>*)m_threadCenterLineExtraction)->GetDistanceMap();
		((CenterLineThread<float>*)m_threadCenterLineExtraction)->GetSpacing(spacing);
		((CenterLineThread<unsigned char>*)m_threadCenterLineExtraction)->Release();
		break;
	case VTK_SHORT:
		num = ((CenterLineThread<short>*)m_threadCenterLineExtraction)->GetBranchAndExtremePoints(m_vectorControlPoints);
		m_pDistanceMap = ((CenterLineThread<short>*)m_threadCenterLineExtraction)->GetDistanceMap();
		((CenterLineThread<float>*)m_threadCenterLineExtraction)->GetSpacing(spacing);
		((CenterLineThread<short>*)m_threadCenterLineExtraction)->Release();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}


	m_pickingCallBack->spacing[0] = spacing[0];
	m_pickingCallBack->spacing[1] = spacing[1];
	m_pickingCallBack->spacing[2] = spacing[2];

	m_ui.m_cbSeedList->clear();

	std::sort(m_vectorControlPoints.begin(), m_vectorControlPoints.end(), sort_nodes);

	printf("control point number: %d\n", (int)m_vectorControlPoints.size());

	//int rangeMin=0;
    int rangeMax=0;
	for (int i = 0; i < num; i++)
	{
		QString str;
		str = QString("%1 %2 %3 %4").arg(m_vectorControlPoints[i].x).arg(m_vectorControlPoints[i].y).arg(m_vectorControlPoints[i].z).arg(m_vectorControlPoints[i].time);

		if ( m_vectorControlPoints[i].time > rangeMax)
			rangeMax = (int)(m_vectorControlPoints[i].time+1);

		m_ui.m_cbSeedList->addItem(str);
	}

// 	m_ui.m_labelUpperMax->setText(QString("%1").arg(rangeMax*10));
// 	m_ui.m_labelLowerMax->setText(QString("%1").arg(rangeMax*10));
// 	m_ui.m_labelUpperMin->setText("0");
// 	m_ui.m_labelLowerMin->setText("0");
// 
// 	m_ui.m_sliderLower->setRange(0, rangeMax*10);
// 	m_ui.m_sliderUpper->setRange(0, rangeMax*10);
// 	m_ui.m_sliderUpper->setValue(rangeMax*10);

	
	std::cout << "Center Line Panel: Get branch points [" << num << " ]" << std::endl;
}

QString CenterLinePanel::transferUI2Display(const QString& text)
{
	Source *source = currentSource();

	vtkImageData* data = source->data();
	double* spaceing = data->GetSpacing();

	QStringList sl = text.split(" ");
	if ( sl.size() != 4)
		return QString("");

	double x = sl[0].toDouble() * spaceing[0];
	double y = sl[1].toDouble() * spaceing[1];
	double z = sl[2].toDouble() * spaceing[2];
	double r = transferRadius(sl[3].toDouble());

	return QString("%1 %2 %3 %4").arg(x).arg(y).arg(z).arg(r);
}


void CenterLinePanel::addSphere(const QString &text)
{
	m_displayModel->addSphere(transferUI2Display(text));
}

void CenterLinePanel::removeSphere(const QString &text)
{
	Source *source = currentSource();

	vtkImageData* data = source->data();
	double* spaceing = data->GetSpacing();

	QStringList sl = text.split(" ");
	if ( sl.size() != 4)
		return;

	double x = (sl[0].toDouble()) * spaceing[0];
	double y = (sl[1].toDouble()) * spaceing[1];
	double z = (sl[2].toDouble()) * spaceing[2];
	double r = transferRadius(sl[3].toDouble());

	QString str = QString("%1 %2 %3 %4").arg(x).arg(y).arg(z).arg(r);

	m_displayModel->removeSphere(str);
}

void CenterLinePanel::slotShowAllPoints()
{
	for (int i = 0; i < m_ui.m_cbSeedList->count(); i++)
	{
		addSphere(m_ui.m_cbSeedList->itemText(i));
	}
}

void CenterLinePanel::slotClearAllPoints()
{
	m_displayModel->removeAllSpheres();

	if ( m_ballDisplayingView)
	{
		disconnect(m_ballDisplayingView, SIGNAL(emitKeyEvent(QKeyEvent*)),
			this, SLOT(slotProcessKeyEventFromView(QKeyEvent*)));
		m_ballDisplayingView = NULL;
	}
}

void CenterLinePanel::slotProcessKeyEventFromView(QKeyEvent* event)
{
	if ( event->type() == QKeyEvent::KeyPress)
	{
		switch(event->key())
		{
		case Qt::Key_Delete:
			cout << "[CenterLinePanel] Key Pressed [Delete]" << endl;
			removeCurrentSelectedActor();
			break;
		case Qt::Key_D:
			cout << "[CenterLinePanel] Key Pressed [D]" << endl;
			processDivisionByClick();
			break;
		case Qt::Key_Control:
			cout << "[CenterLinePanel] Key Control pressed" << endl;
			m_pickingCallBack->keyControlPressed = true;
			break;
		default:
			break;
		}
	}
	else if ( event->type() == QKeyEvent::KeyRelease)
	{

		switch(event->key())
		{
		case Qt::Key_Control:
			cout << "[CenterLinePanel] Key Control released" << endl;
			m_pickingCallBack->keyControlPressed = false;
			break;
		default:
			break;

		}
	}


}

void CenterLinePanel::processDivisionByClick()
{
	Source *source = currentSource();

	if ( m_sourceSkeleton == NULL)
	{
		cout << "source skeleton is NULL" << endl;
		return;
	}


	if (m_sourceSkeleton == source)
	{
		cout << "please select a liver volume" << endl;
		return;
	}

	//if ( m_sourceLiver == NULL)
		m_sourceLiver = source;

	divideLiverByClicking();
}

void CenterLinePanel::divideLiverByClicking()
{
	typedef itk::Image<short, 3> TImageShort3D;
	typedef itk::Image<unsigned char, 3> TImageUChar3D;
	typedef itk::CastImageFilter<TImageShort3D, TImageUChar3D> CastImageFilterShort2UChar;
	//typedef itk::CastImageFilter<TImageShort3D, TImageUChar3D> CastImageFilter2;

	cout << "liver division by clicking" << endl;

	QList<QList<QVector4D>> selectedBranches = m_displayModel->getSelectedBranch();

	if ( selectedBranches.isEmpty())
	{
		cout << "didn't select any branch" << endl;
		cout << "or branch points is less than 4" << endl;
		return;
	}

	TImageUChar3D::Pointer volumeSkeleton = NULL;
	TImageUChar3D::Pointer volumeLiver = NULL;

	if ( m_sourceSkeleton->dataType() == VTK_SHORT)
	{
		cout << "skeleton is short" << endl;
		CastImageFilterShort2UChar::Pointer cast = CastImageFilterShort2UChar::New();
		cast->SetInput(((VolumeSource<TImageShort3D>*)m_sourceSkeleton)->getVolume());
		cast->Update();
		volumeSkeleton = cast->GetOutput();
	}
	else if (m_sourceSkeleton->dataType() == VTK_UNSIGNED_CHAR)
	{
		volumeSkeleton = ((VolumeSource<TImageUChar3D>*)m_sourceSkeleton)->getVolume();
		cout << "skeleton is unsigned char" << endl;
	}
	else
	{
		cout << "skeleton is unknown data type" << endl;
		return;
	}

	if ( m_sourceLiver->dataType() == VTK_SHORT)
	{
		cout << "liver is short" << endl;
		CastImageFilterShort2UChar::Pointer cast = CastImageFilterShort2UChar::New();
		cast->SetInput(((VolumeSource<TImageShort3D>*)m_sourceLiver)->getVolume());
		cast->Update();
		volumeLiver = cast->GetOutput();
	}
	else if (m_sourceLiver->dataType() == VTK_UNSIGNED_CHAR)
	{
		volumeLiver = ((VolumeSource<TImageUChar3D>*)m_sourceLiver)->getVolume();
		cout << "liver is unsigned char" << endl;
	}
	else
	{
		cout << "liver is unknown data type" << endl;
		return;
	}

	// start from the 4th point, divide the skeleton
	TImageUChar3D::SpacingType spacing = volumeLiver->GetSpacing();
	QList<QVector4D> seeds;
	QList<QVector4D> directions;
	
	for (int i = 0; i < selectedBranches.count(); i++)
	{
		QVector4D qseed = selectedBranches.at(i).at(2);
		qseed.setX(qseed.x()/spacing[0]);
		qseed.setY(qseed.y()/spacing[1]);
		qseed.setZ(qseed.z()/spacing[2]);
		seeds.push_back(qseed);

		QVector4D qseedDirection = selectedBranches.at(i).at(3);
		qseedDirection.setX(qseedDirection.x()/spacing[0]);
		qseedDirection.setY(qseedDirection.y()/spacing[1]);
		qseedDirection.setZ(qseedDirection.z()/spacing[2]);
		directions.push_back(qseedDirection);
	}

	divideLiverBySeedWithDirections<TImageUChar3D>(1,seeds, directions, volumeSkeleton, volumeLiver, 0);

// 	divideLiverBySeed<TImageUChar3D>(1,
// 		seed, seedDirection,
// 		volumeSkeleton,
// 		volumeLiver,
// 		NULL, NULL, NULL, NULL, NULL, NULL);

	
}


void CenterLinePanel::removeCurrentSelectedActor()
{
	vtkActor *actor = m_pickingCallBack->getPickedActor();

	if ( actor == NULL) 
		return;

	Source *source = currentSource();
	vtkImageData* data = source->data();
	double* spaceing = data->GetSpacing();
	
	if ( m_displayModel->isALine(actor))
	{
		cout << "ready to delete current line" << endl;

		double start[3];
		double end[3];

		m_displayModel->getLineProperty(actor, start, end);

		if ( start[0]==0 && start[1]==0 && start[2]==0)
		{
			cout << "[error] there is no this actor" << endl;
			return;
		}

		int i = 0;
		for (; i < m_branchNodeList.count(); i++)
		{
			if ( (int)(m_branchNodeList.at(i)->RootPoint.x()) == (int)(start[0]/spaceing[0]) && 
				 (int)(m_branchNodeList.at(i)->RootPoint.y()) == (int)(start[1]/spaceing[1]) && 
				 (int)(m_branchNodeList.at(i)->RootPoint.z()) == (int)(start[2]/spaceing[2]) )
			{
				break;
			}
		}

		if ( i >= m_branchNodeList.count() -1)
		{
			cout << "[error] didn't find branch" << endl;
			return;
		}

		switch(source->dataType())
		{
		case VTK_UNSIGNED_CHAR:
			removeABranch<unsigned char>(m_branchNodeList.at(i));
			break;
		case VTK_SHORT:
			removeABranch<short>(m_branchNodeList.at(i));
			break;
		case VTK_FLOAT:
			removeABranch<float>(m_branchNodeList.at(i));
			break;
		default:
			qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
			break;
		}
	}
	else if ( m_displayModel->isASphere(actor))
	{
		cout << "ready to delete a sphere" << endl;

		QString str = m_pickingCallBack->getPickedPosition();
		for (int i = 0; i < m_ui.m_cbSeedList->count(); i++)
		{
			if (transferUI2Display(m_ui.m_cbSeedList->itemText(i)) == str)
			{
				m_ui.m_cbSeedList->removeItem(i);
				m_displayModel->removeSphere(str);
				return;
			}
		}
	}
	else if ( m_displayModel->isABranch(actor))
	{
		QPair<int,int> pairID = m_displayModel->getBranchID(actor);

		for (int i = 0; i < m_branchNodeList.count(); i++)
		{
			if ( pairID.first == m_branchNodeList[i]->id)
			{
				for (int j = 0; j < m_branchNodeList[i]->Children.count(); j++)
				{
					if ( j == pairID.second)
					{
						m_branchNodeList[i]->SubBranchProperties[i]->useless = true;
						m_displayModel->removeABranch(pairID.first, pairID.second);
						removeNode(m_branchNodeList[i]->Children[j]);
						i = m_branchNodeList.count();
						break;
					}
				}
			}
		}

		//m_displayModel->removeABranch(actor);
	}
	else
	{
		cout << "will not delete this object" << endl;
	}

}


void CenterLinePanel::slotLocateHepaticVein()
{
	QList<BranchNode_t*>::iterator it = m_branchNodeList.begin();

	m_displayModel->clearSelectedBranches();

// 	for (; it != m_branchNodeList.end(); it++)
// 	{
// 		if ( (*it)->Parent == NULL)
// 		{
// 			root = (*it);
// 		}
// 
// 		(*it)->type = NODE_TYPE_PORTAL;
// 	}
// 
// 	if ( root == NULL)
// 	{
// 		cout << "root is NULL" << endl;
// 		return;
// 	}

	QStringList seedlist = autoLocatePortalPoint();
	if ( seedlist.size() != 4)
	{
		qDebug() << "[Error]: cannot find portal point";
		return;
	}

	BranchNode_t *portalNode = NULL;
	for (int i = 0; i < m_branchNodeList.count(); i++)
	{
		if ( seedlist[0].toUInt() == m_branchNodeList.at(i)->RootPoint.x() &&
			seedlist[1].toUInt() == m_branchNodeList.at(i)->RootPoint.y() &&
			seedlist[2].toUInt() == m_branchNodeList.at(i)->RootPoint.z())
		{
			portalNode = m_branchNodeList.at(i); break;
		}
	}

	if ( portalNode == NULL)
	{
		qDebug() << "[Error]: cannot find portal point";
		return;
	}


	QQueue<BranchNode_t*> bnQueue;
	bnQueue.enqueue(portalNode);

	while (1)
	{
		if ( bnQueue.isEmpty())
			break;

		BranchNode_t* currentNode = bnQueue.dequeue();

		if ( currentNode->type == NODE_TYPE_HEPATIC)
		{
			continue;
		}

		for (int i = 0; i < currentNode->Children.size(); i++)
		{
			if (currentNode->RootPoint.w() + 1.0 /*m_ui.m_spinSeparationTh->value()*/ < currentNode->Children[i]->RootPoint.w())
			{
				if ( currentNode->depthFromPortal < 2)
					continue;

				if ( currentNode->RootPoint.w()*1.2 > portalNode->RootPoint.w())
					continue;


				cout << "find hepatic branch" << endl;
				//check more
				currentNode->type = NODE_TYPE_HEPATIC;

				QQueue<BranchNode_t*> tmpQueue;
				for (int j = 0; j < currentNode->Children.count(); j++)
				{
					if ( currentNode->RootPoint.w() + 1.0 < currentNode->Children[j]->RootPoint.w())
					{
						currentNode->Children[j]->type = NODE_TYPE_HEPATIC;
						tmpQueue.enqueue(currentNode->Children[j]);
					}
					else
						currentNode->Children[j]->type = NODE_TYPE_PORTAL;
				}

				while (1)
				{
					if ( tmpQueue.isEmpty()) break;

					BranchNode_t *tmpNode = tmpQueue.dequeue();

					for (int j = 0; j < tmpNode->Children.size(); j++)
					{
						tmpNode->Children[j]->type = NODE_TYPE_HEPATIC;
						tmpQueue.enqueue(tmpNode->Children[j]);

						QVector4D cvt_pnode = tmpNode->RootPoint;
						cvt_pnode.setX(cvt_pnode.x()*m_currentSpacing[0]);
						cvt_pnode.setY(cvt_pnode.y()*m_currentSpacing[1]);
						cvt_pnode.setZ(cvt_pnode.z()*m_currentSpacing[2]);

						QVector4D cvt_cnode =  tmpNode->Children[j]->RootPoint;
						cvt_cnode.setX(cvt_cnode.x()*m_currentSpacing[0]);
						cvt_cnode.setY(cvt_cnode.y()*m_currentSpacing[1]);
						cvt_cnode.setZ(cvt_cnode.z()*m_currentSpacing[2]);

						m_displayModel->setBranchClass(9,  cvt_pnode, cvt_cnode);
					}
				}
			}

			bnQueue.enqueue(currentNode->Children[i]);
		}
	}
}

void CenterLinePanel::slotRemoveHepatic()
{
	QList<BranchNode_t*>::iterator it = m_branchNodeList.begin();
	for (; it != m_branchNodeList.end();)
	{
		printf("children %d, subbranch %d\n", (*it)->Children.size(), (*it)->SubBranches.size());
		if ( (*it)->type == NODE_TYPE_HEPATIC)
		{
			for (int i = 0; i < (*it)->Children.size(); i++)
			{
				if ( (*it)->Children[i]->type == NODE_TYPE_PORTAL)
					continue;

				m_displayModel->removeABranch((*it)->id, i);

				delete (*it)->SubBranches[i];
				delete (*it)->SubBranchProperties[i];
			}

			it = m_branchNodeList.erase(it);
			continue;
		}

		it++;
	}
}




void CenterLinePanel::slotSliderUpperMoved( int )
{
	//m_displayModel->setSphereRadiusRange((double)(m_ui.m_sliderLower->value())*0.02+0.5, (double)(m_ui.m_sliderUpper->value())*0.02+0.5);
}

void CenterLinePanel::slotSliderLowerMoved( int )
{
	//m_displayModel->setSphereRadiusRange((double)(m_ui.m_sliderLower->value())*0.02+0.5, (double)(m_ui.m_sliderUpper->value())*0.02+0.5);
}

double CenterLinePanel::transferRadius( double r )
{
	return r*0.2+1.5;
}

void CenterLinePanel::slotSaveBranchPoints()
{
	QString filename = QFileDialog::getSaveFileName(this,
		tr("Save branch points"), "", tr("Branch Points Files (*.bpf *.*)"));

	if ( filename.isEmpty())
		return;


	if ( m_ui.m_cbSeedList->count() == 0)
		std::cout << "Now branch points" << std::endl;
	else
		std::cout << "Branch points [" << m_ui.m_cbSeedList->count() <<"] will be saved." << endl;
	
	QFile file(filename);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
		return;

	QTextStream out(&file);

	for (int i = 0 ; i < m_ui.m_cbSeedList->count(); i++)
	{
		out << m_ui.m_cbSeedList->itemText(i) << "\n";
	}
	
	file.close();
	std::cout << "Branch points file: " << filename.toLatin1().data() << std::endl;
}

void CenterLinePanel::slotLoadBranchPoints()
{
	QString filename = QFileDialog::getOpenFileName(this,
		tr("Open branch points"), "", tr("Branch Points Files (*.bpf)"));

	if ( filename.isEmpty())
		return;

	m_ui.m_cbSeedList->clear();

	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
		return;

	QTextStream in(&file);
	while (!in.atEnd()) {
		QString line = in.readLine();
		m_ui.m_cbSeedList->addItem(line);
	}

	file.close();
}



void CenterLinePanel::slotRemoveVessel()
{
	m_displayModel->removeRebuiltBranches();
}


void CenterLinePanel::slotRebuildVessel()
{
	Source *source = currentSource();

	if ( !source)
		return;

	m_sourceSkeleton = source;

	bool bResult = false;
	switch(source->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		bResult = rebuildVesselStructure<unsigned char>();
		break;
	case VTK_SHORT:
		bResult = rebuildVesselStructure<short>();
		break;
	case VTK_FLOAT:
		bResult = rebuildVesselStructure<float>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}
}

void CenterLinePanel::slotSmoothVolume()
{
	Source *source = currentSource();
	if(source->type() != stVolume)
		return;

	switch(source->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		createSmoothVolume<unsigned char>(source, 0);
		break;
	case VTK_SHORT:
		createSmoothVolume<short>(source, 0);
		break;
	case VTK_FLOAT:
		createSmoothVolume<float>(source, 0);
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}

	return;
}


void CenterLinePanel::slotLocatePortalPoint()
{
	Source *source = currentSource();
	QStringList strlist = autoLocatePortalPoint();

	if ( strlist.size() == 4)
	{
		QString str = QString("%1 %2 %3 %4").arg(strlist[0]).arg(strlist[1]).arg(strlist[2]).arg(strlist[3].toDouble()+5);
		addSphere(str);
	}
}



void CenterLinePanel::slotTesting1()
{
	Source *source = currentSource();
	QStringList strlist;
	switch(source->dataType())
	{
	case VTK_UNSIGNED_CHAR:
		testSmoothing<unsigned char>();
		break;
	case VTK_SHORT:
		testSmoothing<short>();
		break;
	case VTK_FLOAT:
		testSmoothing<float>();
		break;
	default:
		qDebug() << "[Warning]: Doesn't support data type " << currentSource()->dataType();
		break;
	}
}


void CenterLinePanel::slotTesting2()
{

}


SurfaceSource* CenterLinePanel::volume2SmoothSurface(Source *source, QString label, int intenal)
{
	vtkImageData* data = source->data();
	//double* spaceing = data->GetSpacing();

	double range[2];
	data->GetScalarRange(range);

	vtkContourFilter* contour = vtkContourFilter::New();
	contour->SetInput(data);
	contour->SetValue(0, 1);
	contour->Update();

	printf("pass\n");

	vtkDecimatePro *deci2 = vtkDecimatePro::New();
	deci2->SetInput(contour->GetOutput());
	deci2->PreserveTopologyOn();
	deci2->BoundaryVertexDeletionOn();
	deci2->SetTargetReduction(0.99);

	vtkWarpVector *wrap = vtkWarpVector::New();
	wrap->SetInput(deci2->GetOutput());
	wrap->SetScaleFactor(0.001);

	vtkWindowedSincPolyDataFilter *sinc = vtkWindowedSincPolyDataFilter::New();
	sinc->SetInput(wrap->GetPolyDataOutput());
	if ( intenal == 1)
		sinc->SetNumberOfIterations(50);
	else
		sinc->SetNumberOfIterations(m_ui.m_leSSIteration->text().toInt());
	sinc->BoundarySmoothingOn();
	sinc->SetFeatureAngle(m_ui.m_leSSFeatureAngle->text().toInt());
	sinc->SetEdgeAngle(m_ui.m_leSSEdgeAngle->text().toInt());
	sinc->SetPassBand(0.001);
	sinc->Update();

	printf("pass2\n");

 	SurfaceSource *ssrc = new SurfaceSource(label);
 	ssrc->setData(sinc->GetOutput());

	if ( intenal == 0)
	{
		ssrc->sourceModel();
		ssrc->setSurfaceColor(QColor::fromRgb(255,0,0));
		source->addChild(ssrc);
	}
 
	return ssrc;

// 	source->addChild(ssrc);

	// 	vtkSmoothPolyDataFilter *smooth = vtkSmoothPolyDataFilter::New();
	// 
	// 	smooth->SetInputConnection(sinc->GetOutputPort());
	// 	smooth->SetNumberOfIterations(400);
	// 	smooth->SetFeatureAngle(120);
	// 	smooth->SetEdgeAngle(90);
	// 	smooth->SetRelaxationFactor(0.025);
	// 	smooth->Update();



	// 	vtkSmoothPolyDataFilter *smooth2 = vtkSmoothPolyDataFilter::New();
	// 	smooth2->SetInputConnection(deci2->GetOutputPort());
	// 	smooth2->SetNumberOfIterations(500);

	// 	vtkButterflySubdivisionFilter *subdivision = vtkButterflySubdivisionFilter::New();
	// 	subdivision->SetInputConnection(smooth->GetOutputPort());
	// 	subdivision->SetNumberOfSubdivisions(1);

	// 	vtkDecimatePro *deci3 = vtkDecimatePro::New();
	// 	deci2->SetInputConnection(subdivision->GetOutputPort());
	// 	deci2->PreserveTopologyOn();
	// 	deci2->BoundaryVertexDeletionOn();
	// 	deci2->SetTargetReduction(0.99);

	// 	vtkSmoothPolyDataFilter *smooth3 = vtkSmoothPolyDataFilter::New();
	// 	smooth3->SetInputConnection(subdivision->GetOutputPort());
	// 	smooth3->SetNumberOfIterations(100);



}


void CenterLinePanel::slotCreateSmoothSurface()
{
	Source *source = currentSource();

	if ( source->type() == stVolume)
		volume2SmoothSurface(source, QString("Smoothed"), 0);
}


// void CenterLinePanel::slotTesting2()
// {
// 	QList<QVector4D> qlist;
// 
// 	m_displayModel->addBranch(qlist);
// 	printf("Test2\n");
// 
// 	//Source *source = currentSource();
// 	//vtkImageData* data = source->data();
// 	//double* spaceing = data->GetSpacing();
// 
// 	MakeSphereStructure(6);
// 
// 	printf("x: ");
// 	for(int i = 0; i < m_iSizeSphere; i++)
// 		printf("%d ", m_pIndexSphereX[i]);
// 	printf("\n");
// 
// 	printf("y: ");
// 		for(int i = 0; i < m_iSizeSphere; i++)
// 			printf("%d ", m_pIndexSphereY[i]);
// 	printf("\n");
// 
// 	printf("z: ");
// 		for(int i = 0; i < m_iSizeSphere; i++)
// 			printf("%d ", m_pIndexSphereZ[i]);
// 	printf("\n");
// 
// 	for (int i = 0; i < m_iSizeSphere; i++)
// 	{
// // 		m_displayModel->addSphere((m_pIndexSphereX[i]+190)*spaceing[0], 
// // 			(m_pIndexSphereY[i]+250)*spaceing[1],
// // 			(m_pIndexSphereZ[i]+241)*spaceing[2],
// // 			0.3);
// 
// 		if ( m_pIndexSphereX[i] > 10 || m_pIndexSphereX[i] < -10 ||
// 			 m_pIndexSphereY[i] > 10 || m_pIndexSphereY[i] < -10 ||
// 			 m_pIndexSphereZ[i] > 10 || m_pIndexSphereZ[i] < -10)
// 			continue;
// 
// 		m_displayModel->addSphere(m_pIndexSphereX[i], 
// 			m_pIndexSphereY[i],
// 			m_pIndexSphereZ[i],
// 			0.3);
// 	}
//}

void CenterLinePanel::slotTesting3()
{


// 	typedef itk::Image<short, 3> TImageType;
// 	typedef itk::Image<unsigned char, 3> TOutImageType;
// 
// 	typedef itk::ImageFileReader<TImageType> ImageFileReader;
// 	typedef itk::ImageDuplicator<TOutImageType> ImageDuplicator;
// 	typedef itk::CastImageFilter<TImageType, TOutImageType> CastImageFilter;
// 	typedef itk::AutoCropLabelMapFilter<TImageType> AutoCropLabelMapFilter;
// 	typedef itk::RegionOfInterestImageFilter<TOutImageType, TOutImageType> RegionOfInterestImageFilter;
// 	typedef itk::ImageMaskSpatialObject<3> ImageMaskSpatialObject;
// 	typedef itk::SignedDanielssonDistanceMapImageFilter<TOutImageType, TOutImageType> SignedDanielssonDistanceMapImageFilter;
// 	TIMESTART(" ")
// 
// 	TImageType::Pointer inputImage = ((VolumeSource<TImageType>*)currentSource())->getVolume();
// 
// 	CastImageFilter::Pointer castFilter = CastImageFilter::New();
// 	castFilter->SetInput(inputImage);
// 	castFilter->Update();
// 
// 	//get region of interest
//     ImageMaskSpatialObject::Pointer maskSO = ImageMaskSpatialObject::New();
// 	maskSO->SetImage(castFilter->GetOutput());
// 	maskSO->Update();
//     TOutImageType::RegionType regionType = maskSO->GetAxisAlignedBoundingBoxRegion();
// 
//     RegionOfInterestImageFilter::Pointer roiFilter = RegionOfInterestImageFilter::New();
// 	roiFilter->SetInput(castFilter->GetOutput());
// 	roiFilter->SetRegionOfInterest(regionType);
// 	roiFilter->Update();
// 
// 	// create two volumes
//     ImageDuplicator::Pointer dup1 = ImageDuplicator::New();
// 	dup1->SetInputImage(roiFilter->GetOutput()); dup1->Update();
// // 	ImageDuplicator::Pointer dup2 = ImageDuplicator::New();
// // 	dup2->SetInputImage(roiFilter->GetOutput()); dup2->Update();
// 
// 
//     SignedDanielssonDistanceMapImageFilter::Pointer dmFilter = SignedDanielssonDistanceMapImageFilter::New();
// 	
// 
// 	dmFilter->SetInput(dup1->GetOutput());
// 	//dmFilter->SetInsideValue(1);
// 	//dmFilter->SetOutsideValue(0);
// 	dmFilter->Update();
// 
// 	VolumeSource<TOutImageType> *subsource = 
// 		new VolumeSource<TOutImageType>(QString("DistanceMap#%1").arg(currentSource()->rowCount()+1));
// 	subsource->setVolume(dmFilter->GetOutput());
// 	currentSource()->addChild(subsource);
// 
// 	TIMESTOP("");
// // 	dmFilter->SetInput(dup2->GetOutput());
// // 	VolumeSource<TOutImageType> *subsource = 
// // 		new VolumeSource<TOutImageType>(QString("DistanceMap#%1").arg(currentSource()->rowCount()+1));
// // 	subsource->setVolume(roiFilter->GetOutput());
// // 	currentSource()->addChild(subsource);
}




//CLIPS #include "CLIPSSolution.h"



void CenterLinePanel::slotTestClips()
{
	/* CLIPS
	CLIPSSolution cs;
	cs.addBranchPoints(m_branchNodeList);
	cs.run();

	QStringList classifications = cs.getClassifications();


	double branchclass[4];

	for (int i = 0; i < classifications.count(); i++)
	{
		QString node = classifications.at(i);

		QStringList node_components = node.split(" ");
		if ( node_components.count() != 4)
			continue;

		branchclass[0] = node_components.at(0).toInt();
		branchclass[1] = node_components.at(1).toDouble() * m_currentSpacing[0];
		branchclass[2] = node_components.at(2).toDouble() * m_currentSpacing[1];
		branchclass[3] = node_components.at(3).toDouble() * m_currentSpacing[2];

		m_displayModel->addSphere(branchclass[1], branchclass[2], branchclass[3], 3);

		for (int j = 0; j < m_branchNodeList.count(); j++)
		{
			BranchNode_t* bp = m_branchNodeList.at(j);
			//qDebug("bp root: %d,%d,%d", bp->RootPoint.x(), bp->RootPoint.y(),bp->RootPoint.z());
			//qDebug("node: %d,%d,%d", node_components.at(1).toInt(), node_components.at(2).toInt(), node_components.at(3).toInt());

			if ( bp->RootPoint.x() == node_components.at(1).toInt() &&
				 bp->RootPoint.y() == node_components.at(2).toInt() &&
				 bp->RootPoint.z() == node_components.at(3).toInt())
			{
				//bp->Parent->SubBranches
				QVector4D parentnode = bp->Parent->RootPoint;
				parentnode.setX(parentnode.x()*m_currentSpacing[0]);
				parentnode.setY(parentnode.y()*m_currentSpacing[1]);
				parentnode.setZ(parentnode.z()*m_currentSpacing[2]);

				QVector4D bpnode = bp->RootPoint;
				bpnode.setX(bpnode.x()*m_currentSpacing[0]);
				bpnode.setY(bpnode.y()*m_currentSpacing[1]);
				bpnode.setZ(bpnode.z()*m_currentSpacing[2]);

				m_displayModel->setBranchClass(branchclass[0], parentnode, bpnode);
			}

		}

	}
	*/
}

